#include "Thread.h"
#include "Define.h"
#include <stdio.h>

#ifdef WIN32
#include "windows.h"
#endif

void ThreadManager::createBitfield(int width, int height){
	m_Width = width;
	m_Height = height;
	m_Bitfield.resize(m_Width*m_Height);
}

ThreadManager::ThreadManager(Scene *pScene){
  infos = new Informations();
  infos->setScene(pScene);//la scene est pareille pour toutes les sections alors on peut la definir tout de suite
  m_docount = false;
}
ThreadManager::~ThreadManager(){
  //Libere la memoire
  delete infos;
  infos = 0;
}

int ThreadManager::numberOfCores(){
	int nbCores = 1;
	#ifdef _WIN32
		SYSTEM_INFO sysinfo;
		GetSystemInfo( &sysinfo );
		nbCores = sysinfo.dwNumberOfProcessors;
	#else
		nbCores = sysconf( _SC_NPROCESSORS_ONLN );
	#endif
	return nbCores;
}

void ThreadManager::setScene(Scene *pScene)
{
	if (pScene) infos->setScene(pScene);
}

void ThreadManager::start(Raytracer *raytracer){
	int num_threads;
	num_threads = 1;//numberOfCores();
	if(num_threads <= 0) num_threads = 1;
	#ifdef DEBUG
    //printf("Number of threads: %d\n",num_threads);
	#endif

	if (raytracer)
		m_Raytracer = raytracer;
	startThreads(infos, m_Raytracer, num_threads);
}

void ThreadManager::waitForEnd(){
	for(int i = 0; i < m_NumThreads; i++) {
		lst_threads[i]->join();//attends que le i-nieme thread aie fini
		delete lst_threads[i];
		lst_threads[i] = NULL;
	}

	lst_threads.clear();
}

void ThreadManager::startThreads(Informations *info, Raytracer *raytracer, int num_threads)
{
	m_NumThreads = num_threads;
	m_Raytracer = raytracer;
	for (int i = 0; i < m_NumThreads; i++) {
		boost::thread *t = new boost::thread(boost::bind(&ThreadManager::runSingleThread, this));
		lst_threads.push_back(t);
	}
	waitForEnd();

	m_Bitfield.reset();
}

void ThreadManager::runSingleThread()
{
    float totalinv = 100.0f/(m_Raytracer->getXOffset()*m_Raytracer->getYOffset());
	for (int i = 0; i < m_Raytracer->getXOffset(); i++) {
		for (int j = 0; j < m_Raytracer->getYOffset(); j++) {
			if (m_docount){printf("%d\n", (int)((i*m_Height+j)*totalinv));}
            fflush(stdout);
			if (!checkBitField(i, j)) {
				
				m_Raytracer->raytrace(i, j);
			}
		}
	}
    if (m_docount){printf("100\n");}
} 

bool ThreadManager::checkBitField(int x, int y)
{
	// On lock le mutex
	boost::mutex::scoped_lock l(m_Mutex);
	if (!m_Bitfield[x*m_Height+y]) {
		m_Bitfield.set(x*m_Height+y, true);
		return false;
	}

	return true;
} 
